﻿#region Copyright information
// 
// Copyright © 2005-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the Biological Object Library and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: TreeNode.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@gmail.com
// - Date Created: 2013-01-24 4:34 PM
// - Last Modified: 2013-01-25 3:59 PM
// 
#endregion
using System;
using System.Collections.Generic;
using System.Linq;

namespace BOL.Algorithms.Tree
{
    public class TreeNode<T> : ITreeNode<T>
    {
        #region Public properties

        public T Value { get; set; }

        public bool IsRoot { get { return Parent == null; } }

        public bool IsLeaf { get { return ChildCount == 0; } }

        public ITreeNode<T> Parent { get; set; }

        public IList<ITreeNode<T>> Children { get; set; }

        public int ChildCount { get { return Children.Count; } }

        public int Depth
        {
            get
            {
                var depth = 0;
                ITreeNode<T> node = this;

                while (node.Parent != null)
                {
                    node = node.Parent;
                    depth++;
                }

                return depth;
            }
        }

        #endregion

        #region Constructors

        public TreeNode(T value, IEnumerable<ITreeNode<T>> children)
        {
            Value = value;
            Children = new List<ITreeNode<T>>(children);
        }

        public TreeNode(T value)
            : this(value, new List<ITreeNode<T>>())
        {
        }

        #endregion

        #region ICloneable implementation

        public ITreeNode<T> Clone()
        {
            return new TreeNode<T>(Value, Children.Select(x => x.Clone() as ITreeNode<T>));
        }

        object ICloneable.Clone()
        {
            return Clone();
        }

        #endregion

        #region Public methods

        public ITreeNode<T> ChildAt(int index)
        {
            return Children[index];
        }

        public void Add(ITreeNode<T> child)
        {
            child.Parent = this;
            Children.Add(child);
        }

        public bool ContainsChild(ITreeNode<T> child)
        {
            return Children.Contains(child);
        }

        public void Insert(int index, ITreeNode<T> child)
        {
            child.Parent = this;
            Children.Insert(index, child);
        }

        public void RemoveAt(int index)
        {
            Remove(Children[index]);
        }

        public void Remove(ITreeNode<T> child)
        {
            child.Parent = null;
            Children.Remove(child);
        }

        public void RemoveFromParent()
        {
            Parent.Remove(this);
        }

        #endregion

        #region IEquatable<ITreeNode<T>> implementation

        public bool Equals(ITreeNode<T> other)
        {
            if (other == null)
                throw new ArgumentNullException("other");

            return Value.Equals(other.Value) & Children.SequenceEqual(other.Children);
        }

        #endregion

        #region Object overriden

        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        public override bool Equals(object other)
        {
            if (other == null)
                throw new ArgumentNullException("other");

            if (!(other is ITreeNode<T>))
                throw new InvalidCastException("The 'other' argument is not a ITreeNode<T> object.");

            return Equals(other as ITreeNode<T>);
        }

        public override string ToString()
        {
            return Value.ToString();
        }

        #endregion
    }
}